using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
using System.Security.Cryptography;
using System.Text.Json;
using SumerCoreDevOps.Domain.Entities;
using SumerCoreDevOps.Infrastructure.Data;
using SumerCoreDevOps.Infrastructure.Distributed;
using SumerCoreDevOps.Infrastructure.Realtime;
using SumerCoreDevOps.Shared.Models.Messages;

namespace SumerCoreDevOps.Infrastructure.Scheduling;

/// <summary>
/// 节点管理器 (支持多主节点分布式架构)
/// </summary>
public class NodeManager
{
    private readonly FreeSQLProvider _dbProvider;
    private readonly ILogger<NodeManager> _logger;
    private readonly IRealtimeNotificationService? _realtimeService;
    private readonly IDistributedCoordinator? _coordinator;
    private readonly ConcurrentDictionary<long, NodeStatus> _onlineNodes = new();
    private readonly ConcurrentDictionary<long, DateTime> _lastHeartbeats = new();
    private readonly bool _useDistributedMode;

    public NodeManager(
        FreeSQLProvider dbProvider,
        ILogger<NodeManager> logger,
        IRealtimeNotificationService? realtimeService = null,
        IDistributedCoordinator? coordinator = null)
    {
        _dbProvider = dbProvider;
        _logger = logger;
        _realtimeService = realtimeService;
        _coordinator = coordinator;
        _useDistributedMode = coordinator != null;

        if (_useDistributedMode)
        {
            _logger.LogInformation("NodeManager启动在分布式模式，使用Redis协调");
        }
        else
        {
            _logger.LogInformation("NodeManager启动在单机模式");
        }

        // 启动心跳检查任务
        _ = Task.Run(HeartbeatMonitorAsync);
    }

    /// <summary>
    /// 注册节点
    /// </summary>
    public async Task<NodeStatus> RegisterNodeAsync(NodeRegisterMessage message)
    {
        // 检查是否已存在
        var existingNode = await _dbProvider.Orm.Select<NodeStatus>()
            .Where(n => n.NodeKey == message.NodeKey)
            .FirstAsync();

        if (existingNode != null)
        {
            // 如果ConnectionToken不存在，生成新的ConnectionToken
            if (string.IsNullOrEmpty(existingNode.ConnectionToken))
            {
                existingNode.ConnectionToken = GenerateConnectionToken();
            }

            // 更新节点信息
            await _dbProvider.Orm.Update<NodeStatus>()
                .Set(n => n.NodeName, message.NodeName)
                .Set(n => n.IsOnline, true)
                .Set(n => n.ConnectionToken, existingNode.ConnectionToken)
                .Set(n => n.SupportedEnvironments, JsonSerializer.Serialize(message.SupportedEnvironments))
                .Set(n => n.HardwareInfo, JsonSerializer.Serialize(message.HardwareInfo))
                .Set(n => n.LastHeartbeatTime, DateTime.UtcNow)
                .Where(n => n.Id == existingNode.Id)
                .ExecuteAffrowsAsync();

            existingNode.NodeName = message.NodeName;
            existingNode.IsOnline = true;
            existingNode.SupportedEnvironments = JsonSerializer.Serialize(message.SupportedEnvironments);
            existingNode.HardwareInfo = JsonSerializer.Serialize(message.HardwareInfo);
            existingNode.LastHeartbeatTime = DateTime.UtcNow;

            _onlineNodes.TryAdd(existingNode.Id, existingNode);
            _lastHeartbeats.TryAdd(existingNode.Id, DateTime.UtcNow);

            _logger.LogInformation("节点重新注册: NodeKey={NodeKey}, NodeId={NodeId}", message.NodeKey, existingNode.Id);

            // 推送节点上线事件
            await PushNodeStatusChangeAsync(existingNode, "online");

            return existingNode;
        }
        else
        {
            // 创建新节点
            var node = new NodeStatus
            {
                NodeKey = message.NodeKey,
                NodeName = message.NodeName,
                ConnectionToken = GenerateConnectionToken(),
                IsOnline = true,
                SupportedEnvironments = JsonSerializer.Serialize(message.SupportedEnvironments),
                HardwareInfo = JsonSerializer.Serialize(message.HardwareInfo),
                LastHeartbeatTime = DateTime.UtcNow
            };

            node.Id = (long)await _dbProvider.Orm.Insert(node).ExecuteIdentityAsync();

            _onlineNodes.TryAdd(node.Id, node);
            _lastHeartbeats.TryAdd(node.Id, DateTime.UtcNow);

            _logger.LogInformation("节点注册成功: NodeKey={NodeKey}, NodeId={NodeId}", message.NodeKey, node.Id);

            // 推送节点上线事件
            await PushNodeStatusChangeAsync(node, "registered");

            return node;
        }
    }

    /// <summary>
    /// 处理心跳
    /// </summary>
    public async Task HandleHeartbeatAsync(long nodeId, HeartbeatMessage message)
    {
        var now = DateTime.UtcNow;
        _lastHeartbeats.AddOrUpdate(nodeId, now, (_, _) => now);

        var heartbeatData = new
        {
            message.RunningTaskCount,
            message.CpuUsage,
            message.MemoryUsage,
            message.AvailableDiskSpaceMB,
            Timestamp = now
        };

        var loadData = JsonSerializer.Serialize(heartbeatData);

        // 在分布式模式下，将心跳存储到Redis
        if (_useDistributedMode && _coordinator != null)
        {
            try
            {
                // 存储心跳到Redis，60秒TTL
                await _coordinator.SetAsync($"heartbeat:{nodeId}", heartbeatData, TimeSpan.FromSeconds(60));

                // 记录节点连接到此主节点（用于消息路由）
                var masterNodeManager = GetMasterNodeManager();
                if (masterNodeManager != null)
                {
                    await _coordinator.HashSetAsync($"node:{nodeId}:connections", masterNodeManager.MasterId, now);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "保存心跳到Redis失败: NodeId={NodeId}", nodeId);
            }
        }

        // 更新数据库
        await _dbProvider.Orm.Update<NodeStatus>()
            .Set(n => n.IsOnline, true)
            .Set(n => n.LastHeartbeatTime, now)
            .Set(n => n.LoadData, loadData)
            .Where(n => n.Id == nodeId)
            .ExecuteAffrowsAsync();

        _logger.LogDebug("收到心跳: NodeId={NodeId}, RunningTasks={RunningTasks}, CPU={CPU}%, Memory={Memory}%",
            nodeId, message.RunningTaskCount, message.CpuUsage, message.MemoryUsage);
    }

    // 用于获取MasterNodeManager实例的辅助方法（将在Program.cs中设置）
    private static MasterNodeManager? _masterNodeManagerInstance;
    public static void SetMasterNodeManager(MasterNodeManager manager) => _masterNodeManagerInstance = manager;
    private MasterNodeManager? GetMasterNodeManager() => _masterNodeManagerInstance;

    /// <summary>
    /// 节点下线
    /// </summary>
    public async Task NodeOfflineAsync(long nodeId)
    {
        _onlineNodes.TryRemove(nodeId, out var node);
        _lastHeartbeats.TryRemove(nodeId, out _);

        await _dbProvider.Orm.Update<NodeStatus>()
            .Set(n => n.IsOnline, false)
            .Where(n => n.Id == nodeId)
            .ExecuteAffrowsAsync();

        _logger.LogWarning("节点下线: NodeId={NodeId}", nodeId);

        // 推送节点下线事件
        if (node != null)
        {
            node.IsOnline = false;
            await PushNodeStatusChangeAsync(node, "offline");
        }
    }

    /// <summary>
    /// 获取在线节点
    /// </summary>
    public async Task<List<NodeStatus>> GetOnlineNodesAsync()
    {
        return await _dbProvider.Orm.Select<NodeStatus>()
            .Where(n => n.IsOnline)
            .ToListAsync();
    }

    /// <summary>
    /// 根据环境选择合适的节点
    /// </summary>
    public async Task<NodeStatus?> SelectNodeForEnvironmentAsync(string environment)
    {
        var onlineNodes = await GetOnlineNodesAsync();

        // 筛选支持目标环境的节点
        var candidateNodes = onlineNodes.Where(n =>
        {
            var environments = JsonSerializer.Deserialize<List<string>>(n.SupportedEnvironments);
            return environments?.Contains(environment) == true;
        }).ToList();

        if (candidateNodes.Count == 0)
        {
            _logger.LogWarning("没有找到支持环境 '{Environment}' 的在线节点", environment);
            return null;
        }

        // 选择负载最低的节点
        NodeStatus? selectedNode = null;
        double minLoad = double.MaxValue;

        foreach (var node in candidateNodes)
        {
            if (string.IsNullOrEmpty(node.LoadData)) continue;

            try
            {
                var loadData = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(node.LoadData);
                if (loadData == null) continue;

                var cpuUsage = loadData["cpuUsage"].GetDouble();
                var memoryUsage = loadData["memoryUsage"].GetDouble();
                var runningTasks = loadData["runningTaskCount"].GetInt32();

                // 综合负载评分（可自定义权重）
                double load = (cpuUsage * 0.3) + (memoryUsage * 0.3) + (runningTasks * 10 * 0.4);

                if (load < minLoad)
                {
                    minLoad = load;
                    selectedNode = node;
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "解析节点负载数据失败: NodeId={NodeId}", node.Id);
            }
        }

        if (selectedNode != null)
        {
            _logger.LogInformation("选择节点: NodeId={NodeId}, NodeName={NodeName}, Load={Load}",
                selectedNode.Id, selectedNode.NodeName, minLoad);
        }

        return selectedNode;
    }

    /// <summary>
    /// 获取节点统计信息
    /// </summary>
    public async Task<NodeStatistics> GetStatisticsAsync()
    {
        var allNodes = await _dbProvider.Orm.Select<NodeStatus>().ToListAsync();

        return new NodeStatistics
        {
            TotalNodes = allNodes.Count,
            OnlineNodes = allNodes.Count(n => n.IsOnline),
            OfflineNodes = allNodes.Count(n => !n.IsOnline)
        };
    }

    /// <summary>
    /// 心跳监控任务
    /// </summary>
    private async Task HeartbeatMonitorAsync()
    {
        while (true)
        {
            try
            {
                await Task.Delay(TimeSpan.FromSeconds(30));

                if (_useDistributedMode && _coordinator != null)
                {
                    // 分布式模式：检查Redis中的心跳
                    await MonitorDistributedHeartbeatsAsync();
                }
                else
                {
                    // 单机模式：检查本地心跳
                    var now = DateTime.UtcNow;
                    var timeoutThreshold = now.AddSeconds(-90); // 90秒超时

                    var timedOutNodes = _lastHeartbeats
                        .Where(kv => kv.Value < timeoutThreshold)
                        .Select(kv => kv.Key)
                        .ToList();

                    foreach (var nodeId in timedOutNodes)
                    {
                        await NodeOfflineAsync(nodeId);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "心跳监控任务异常");
            }
        }
    }

    /// <summary>
    /// 监控分布式心跳
    /// </summary>
    private async Task MonitorDistributedHeartbeatsAsync()
    {
        if (_coordinator == null) return;

        try
        {
            // 获取所有在线节点
            var onlineNodes = await GetOnlineNodesAsync();

            foreach (var node in onlineNodes)
            {
                // 检查Redis中是否存在心跳
                var heartbeatExists = await _coordinator.ExistsAsync($"heartbeat:{node.Id}");

                if (!heartbeatExists)
                {
                    // Redis中没有心跳记录，说明节点已超时
                    _logger.LogWarning("节点心跳超时（Redis中无记录）: NodeId={NodeId}", node.Id);
                    await NodeOfflineAsync(node.Id);
                }
            }

            // 同时检查本地心跳缓存
            var now = DateTime.UtcNow;
            var timeoutThreshold = now.AddSeconds(-90);

            var localTimedOutNodes = _lastHeartbeats
                .Where(kv => kv.Value < timeoutThreshold)
                .Select(kv => kv.Key)
                .ToList();

            foreach (var nodeId in localTimedOutNodes)
            {
                // 双重检查：如果Redis中也没有，才标记为离线
                var heartbeatExists = await _coordinator.ExistsAsync($"heartbeat:{nodeId}");
                if (!heartbeatExists)
                {
                    await NodeOfflineAsync(nodeId);
                }
                else
                {
                    // Redis中有心跳，说明其他主节点收到了，更新本地缓存
                    _lastHeartbeats.TryUpdate(nodeId, now, _lastHeartbeats[nodeId]);
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "监控分布式心跳失败");
        }
    }

    /// <summary>
    /// 推送节点状态变化到前端
    /// </summary>
    private async Task PushNodeStatusChangeAsync(NodeStatus node, string eventType)
    {
        if (_realtimeService == null) return;

        // 解析负载数据
        Dictionary<string, JsonElement>? loadData = null;
        if (!string.IsNullOrEmpty(node.LoadData))
        {
            try
            {
                loadData = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(node.LoadData);
            }
            catch
            {
                // 忽略解析错误
            }
        }

        // 解析支持的环境
        List<string>? environments = null;
        if (!string.IsNullOrEmpty(node.SupportedEnvironments))
        {
            try
            {
                environments = JsonSerializer.Deserialize<List<string>>(node.SupportedEnvironments);
            }
            catch
            {
                // 忽略解析错误
            }
        }

        var nodeStatusData = new
        {
            nodeId = node.Id,
            nodeName = node.NodeName,
            nodeKey = node.NodeKey,
            isOnline = node.IsOnline,
            cpuUsage = loadData?.ContainsKey("cpuUsage") == true ? loadData["cpuUsage"].GetDouble() : 0.0,
            memoryUsage = loadData?.ContainsKey("memoryUsage") == true ? loadData["memoryUsage"].GetDouble() : 0.0,
            runningTasks = loadData?.ContainsKey("runningTaskCount") == true ? loadData["runningTaskCount"].GetInt32() : 0,
            availableDiskSpaceMB = loadData?.ContainsKey("availableDiskSpaceMB") == true ? loadData["availableDiskSpaceMB"].GetInt64() : 0L,
            supportedEnvironments = environments,
            lastHeartbeatTime = node.LastHeartbeatTime,
            eventType = eventType,
            timestamp = DateTime.UtcNow
        };

        await _realtimeService.PushNodeStatusAsync(nodeStatusData);
    }

    /// <summary>
    /// 生成连接令牌（Connection Token）
    /// 用于节点重连认证的持久化令牌
    /// </summary>
    private string GenerateConnectionToken()
    {
        var randomBytes = RandomNumberGenerator.GetBytes(32);
        var token = Convert.ToBase64String(randomBytes)
            .Replace("+", "")
            .Replace("/", "")
            .Replace("=", "");

        // 如果长度超过 48 个字符，截取前 48 个字符
        if (token.Length > 48)
        {
            token = token.Substring(0, 48);
        }

        return token;
    }

    /// <summary>
    /// 验证节点认证
    /// </summary>
    public async Task<(bool isValid, NodeStatus? node, string? errorMessage)> AuthenticateNodeAsync(NodeAuthMessage message)
    {
        try
        {
            // 查找节点
            var node = await _dbProvider.Orm.Select<NodeStatus>()
                .Where(n => n.Id == message.NodeId && n.NodeKey == message.NodeKey)
                .FirstAsync();

            if (node == null)
            {
                return (false, null, "节点不存在");
            }

            // 验证ConnectionToken
            if (node.ConnectionToken != message.ConnectionToken)
            {
                _logger.LogWarning("节点认证失败: NodeId={NodeId}, 令牌不匹配", message.NodeId);
                return (false, null, "认证令牌无效");
            }

            // 更新节点状态
            await _dbProvider.Orm.Update<NodeStatus>()
                .Set(n => n.NodeName, message.NodeName)
                .Set(n => n.IsOnline, true)
                .Set(n => n.HardwareInfo, JsonSerializer.Serialize(message.HardwareInfo))
                .Set(n => n.LastHeartbeatTime, DateTime.UtcNow)
                .Where(n => n.Id == node.Id)
                .ExecuteAffrowsAsync();

            node.NodeName = message.NodeName;
            node.IsOnline = true;
            node.HardwareInfo = JsonSerializer.Serialize(message.HardwareInfo);
            node.LastHeartbeatTime = DateTime.UtcNow;

            _onlineNodes.TryAdd(node.Id, node);
            _lastHeartbeats.TryAdd(node.Id, DateTime.UtcNow);

            _logger.LogInformation("节点认证成功: NodeId={NodeId}, NodeKey={NodeKey}", node.Id, node.NodeKey);
            return (true, node, null);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "节点认证异常: NodeId={NodeId}", message.NodeId);
            return (false, null, $"认证异常: {ex.Message}");
        }
    }
}

/// <summary>
/// 节点统计信息
/// </summary>
public class NodeStatistics
{
    public int TotalNodes { get; set; }
    public int OnlineNodes { get; set; }
    public int OfflineNodes { get; set; }
}
